#include "macro.h"

#include <stdio.h>
#include <stdlib.h>

#include "logger.h"
#include "misc.h"
#include "color.h"


#define memoryReadFail(h, a)        memoryReadFailReal(h, a, __FUNCTION__)
#define memoryWriteFail(h, a)       memoryWriteFailReal(h, a, __FUNCTION__)

Macro *Macro::pinstance = NULL;

Macro::Macro()
{
    mouseDevice = NULL;
    keyboardDevice = NULL;
    processDevice = NULL;
    memoryDevice = NULL;
    filesystemDevice = NULL;
    networkDevice = NULL;
    timerDevice = NULL;
	ipcDevice = NULL;
	audioDevice = NULL;

    attachedHwnd = NULL;

    warningsEnabled = true;
	wineMode = false;
    enableSound = true;
}

Macro *Macro::instance()
{
    if( !pinstance )
        pinstance = new Macro;

    return pinstance;
}

int Macro::modifyPermission(HANDLE hProcess, const char *PrivName, bool allow)
{
    HANDLE hToken;
    LUID sedebugnameValue;
    TOKEN_PRIVILEGES tkp;

    if ( !OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES
        | TOKEN_QUERY,&hToken ) )
    {
        CloseHandle(hToken);
        return false;
    }

    //Don't bother looking up and adjusting priviledge if removing rights
    if(allow)
    {
        if ( !LookupPrivilegeValue( NULL, PrivName, &sedebugnameValue ) )
        {
            CloseHandle( hToken );
            return false;
        }

        tkp.PrivilegeCount = 1;
        tkp.Privileges[0].Luid = sedebugnameValue;
        tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    }

    if (AdjustTokenPrivileges( hToken, false, &tkp, sizeof tkp,
        NULL, NULL ) == 0)
    {
        CloseHandle(hToken);
        return false;
    }

    CloseHandle(hToken);
    return true;
}

int Macro::init(CLI_OPTIONS *pclio, CONFIG_OPTIONS *pco)
{
    // Make use of any necessary config options
    if( pco )
    {
        enableSound = pco->enableSound;
    }
	else
	{
		enableSound = true;
	}

    if( mouseDevice || keyboardDevice || processDevice || memoryDevice
        || filesystemDevice || networkDevice || timerDevice  ||
		ipcDevice || audioDevice )
        return false;

    mouseDevice = new MouseDevice;
    if( !mouseDevice ) {
        Logger::instance()->add("Failed to create mouse device.\n");
        return false; }

    keyboardDevice = new KeyboardDevice;
    if( !keyboardDevice ) {
        Logger::instance()->add("Failed to create keyboard device.\n");
        return false; }

    processDevice = new ProcessDevice;
    if( !processDevice ) {
        Logger::instance()->add("Failed to create process device.\n");
        return false; }

    filesystemDevice = new FilesystemDevice;
    if( !filesystemDevice ) {
        Logger::instance()->add("Failed to create filesystem device.\n");
        return false; }

    networkDevice = new NetworkDevice;
    if( !networkDevice ) {
        Logger::instance()->add("Failed to create network device.\n");
        return false; }

    timerDevice = new TimerDevice;
    if( !timerDevice ) {
        Logger::instance()->add("Failed to create timer device.\n");
        return false; }

	ipcDevice = new IpcDevice;
	if( !ipcDevice ) {
		Logger::instance()->add("Failed to create IPC device.\n");
		return false; }

    if( enableSound )
    {
        audioDevice = new AudioDevice;
        if( !audioDevice ) {
            Logger::instance()->add("Failed to create audio device.\n");
            return false; }
    }

    /* Set debug privileges on self */
    HANDLE ourProcess = OpenProcess(PROCESS_QUERY_INFORMATION,
        false, GetCurrentProcessId());
    if( !modifyPermission(GetCurrentProcess(), "SeDebugPrivilege", true) )
        Logger::instance()->add("Warning: Failed to enable SeDebugPrivilege.");
    CloseHandle(ourProcess);


	/* Set options */
	if( pclio )
	{
		wineMode = pclio->wineMode;
		keyboardDevice->setWineMode(wineMode);
		mouseDevice->setWineMode(wineMode);
	}

    return true;
}

int Macro::cleanup()
{
    delete mouseDevice;
    delete keyboardDevice;
    delete processDevice;
    delete memoryDevice;
    delete filesystemDevice;
    delete networkDevice;
    delete timerDevice;
	delete ipcDevice;
    delete audioDevice;

    mouseDevice = NULL;
    keyboardDevice = NULL;
    processDevice = NULL;
    memoryDevice = NULL;
    filesystemDevice = NULL;
    networkDevice = NULL;
    timerDevice = NULL;
	ipcDevice = NULL;
    audioDevice = NULL;

    return true;
}


/* Mouse Functions */
void Macro::mouseSetDelay(unsigned int delay)
{
    mouseDevice->setDelay(delay);
}

void Macro::mouseMove(int x, int y)
{
    if( mouseDevice->getAttachedHwnd() )
        processDevice->reattach();

    mouseDevice->move(x, y);

    if( mouseDevice->getAttachedHwnd() )
        processDevice->detach_temp();
}

void Macro::mouseSet(int x, int y)
{
    if( mouseDevice->getAttachedHwnd() )
        processDevice->reattach();

    mouseDevice->set(x, y);

    if( mouseDevice->getAttachedHwnd() )
        processDevice->detach_temp();
}

void Macro::mouseLHold()
{
    if( mouseDevice->getAttachedHwnd() )
        processDevice->reattach();

    mouseDevice->leftHold();

    if( mouseDevice->getAttachedHwnd() )
        processDevice->detach_temp();
}

void Macro::mouseLRelease()
{
    if( mouseDevice->getAttachedHwnd() )
        processDevice->reattach();

    mouseDevice->leftRelease();

    if( mouseDevice->getAttachedHwnd() )
        processDevice->detach_temp();
}

void Macro::mouseLClick(unsigned int modifier)
{
    if( mouseDevice->getAttachedHwnd() )
        processDevice->reattach();

    mouseDevice->leftClick(modifier);

    if( mouseDevice->getAttachedHwnd() )
        processDevice->detach_temp();
}

void Macro::mouseMHold()
{
    if( mouseDevice->getAttachedHwnd() )
        processDevice->reattach();

    mouseDevice->middleHold();

    if( mouseDevice->getAttachedHwnd() )
        processDevice->detach_temp();
}

void Macro::mouseMRelease()
{
    if( mouseDevice->getAttachedHwnd() )
        processDevice->reattach();

    mouseDevice->middleRelease();

    if( mouseDevice->getAttachedHwnd() )
        processDevice->detach_temp();
}

void Macro::mouseMClick(unsigned int modifier)
{
    if( mouseDevice->getAttachedHwnd() )
        processDevice->reattach();

    mouseDevice->middleClick(modifier);

    if( mouseDevice->getAttachedHwnd() )
        processDevice->detach_temp();
}

void Macro::mouseRHold()
{
    if( mouseDevice->getAttachedHwnd() )
        processDevice->reattach();

    mouseDevice->rightHold();

    if( mouseDevice->getAttachedHwnd() )
        processDevice->detach_temp();
}

void Macro::mouseRRelease()
{
    if( mouseDevice->getAttachedHwnd() )
        processDevice->reattach();

    mouseDevice->rightRelease();

    if( mouseDevice->getAttachedHwnd() )
        processDevice->detach_temp();
}

void Macro::mouseRClick(unsigned int modifier)
{
    if( mouseDevice->getAttachedHwnd() )
        processDevice->reattach();

    mouseDevice->rightClick(modifier);

    if( mouseDevice->getAttachedHwnd() )
        processDevice->detach_temp();
}

void Macro::mouseWheelMove(int delta)
{
    if( mouseDevice->getAttachedHwnd() )
        processDevice->reattach();

    mouseDevice->wheelMove(delta);

    if( mouseDevice->getAttachedHwnd() )
        processDevice->detach_temp();
}

int Macro::mouseGetX()
{
    return mouseDevice->getX();
}

int Macro::mouseGetY()
{
    return mouseDevice->getY();
}



/* Keyboard functions */
void Macro::keyboardSetDelay(unsigned int delay)
{
    keyboardDevice->setDelay(delay);
}

void Macro::keyboardHold(unsigned int key, unsigned int modifier)
{
    if( keyboardDevice->getAttachedHwnd() )
        processDevice->reattach();

    keyboardDevice->keyHold(key, modifier);

    if( keyboardDevice->getAttachedHwnd() )
        processDevice->detach_temp();
}

void Macro::keyboardRelease(unsigned int key, unsigned int modifier)
{
    if( keyboardDevice->getAttachedHwnd() )
        processDevice->reattach();

    keyboardDevice->keyRelease(key, modifier);

    if( keyboardDevice->getAttachedHwnd() )
        processDevice->detach_temp();
}

void Macro::keyboardPress(unsigned int key, unsigned int modifier)
{
    if( keyboardDevice->getAttachedHwnd() )
        processDevice->reattach();

    keyboardDevice->keyPress(key, modifier);

    if( keyboardDevice->getAttachedHwnd() )
        processDevice->detach_temp();
}

void Macro::keyboardState(BYTE *ks)
{
	GetKeyState(0);
	GetKeyboardState(ks);
	for(unsigned int i = 0; i < 256; i++)
	{
		ks[i] = (ks[i] & 0x80) != 0;
	}
}

bool Macro::keyPressed(unsigned int key)
{
    return keyboardDevice->keyPressed(key);
}

bool Macro::keyPressedLocal(unsigned int key)
{
    return keyboardDevice->keyPressedLocal(key);
}

void Macro::keyboardType(const char *message)
{
    if( keyboardDevice->getAttachedHwnd() )
        processDevice->reattach();

    keyboardDevice->type(message);

    if( keyboardDevice->getAttachedHwnd() )
        processDevice->detach_temp();
}

void Macro::keyboardBufferClear()
{
    keyboardDevice->clearBuffer();
}

std::string Macro::getKeyName(unsigned int key)
{
    return keyboardDevice->getKeyName(key);
}


/* Process functions */
int Macro::attach(HWND hwnd)
{
    if( processDevice->attach(hwnd) )
    {
        mouseDevice->setAttachedInput(hwnd);
        keyboardDevice->setAttachedInput(hwnd);

        processDevice->detach_temp(); // TEST
        return true;
    }
    else
    {
        Logger::instance()->add("Failed to attach to handle 0x%X."
            " Error code: %d (%s).\n", hwnd, GetLastError(),
            getSystemError(GetLastError()).c_str());
        return false;
    }
}

int Macro::attachKeyboard(HWND hwnd)
{
	if( processDevice->attach(hwnd) )
	{
		keyboardDevice->setAttachedInput(hwnd);
        processDevice->detach_temp(); // TEST
		return true;
	}
    else
    {
        Logger::instance()->add("Failed to attach keyboard to handle 0x%X."
            " Error code: %d (%s).\n", hwnd, GetLastError(),
            getSystemError(GetLastError()).c_str());
        return false;
    }
}

int Macro::attachMouse(HWND hwnd)
{
	if( processDevice->attach(hwnd) )
	{
		mouseDevice->setAttachedInput(hwnd);
        processDevice->detach_temp(); // TEST
		return true;
	}
    else
    {
        Logger::instance()->add("Failed to attach keyboard to handle 0x%X."
            " Error code: %d (%s).\n", hwnd, GetLastError(),
            getSystemError(GetLastError()).c_str());
        return false;
    }
}

int Macro::detach()
{
    HWND prevHwnd = processDevice->getAttachedHwnd();
    mouseDevice->setAttachedInput(NULL);
    keyboardDevice->setAttachedInput(NULL);
    int success = processDevice->detach();

    if( !success )
        Logger::instance()->add("Failed to detach from process (%x).", prevHwnd);

    return success;
}

int Macro::forcedDetach()
{
    Logger::instance()->add("Forced detach due to invalid handle.");
    int success = detach();

    return success;
}

HWND Macro::getAttachedHwnd()
{
    return processDevice->getAttachedHwnd();
}

HANDLE Macro::openProcess(int proc)
{
    HANDLE handle = processDevice->openProcess(proc);

    if( !handle )
    {
        int err = GetLastError();
        Logger::instance()->add("Error attempting to open process 0x%X. "\
        "Error code: %i (%s).", proc, err, getSystemError(err).c_str());
    }

    return handle;
}

void Macro::closeProcess(HANDLE &handle)
{
    processDevice->closeProcess(handle);
}

DWORD Macro::findProcess(std::string name, int &err)
{
    DWORD proc = processDevice->findProcess(name, err);

    if( err )
        Logger::instance()->add("findProcess() exited with error code %d (%s).",
            err, getSystemError(err).c_str());
    else if( !proc )
        Logger::instance()->add("findProcess() returned 0. Process not found "\
            "or other error occured.");

    return proc;
}

DWORD Macro::findProcessByExe(std::string name, int & err)
{
    DWORD proc = processDevice->findProcessByExe(name, err);

    if( err )
        Logger::instance()->add("findProcessByExe() exited with error code "\
            "%d (%s).", err, getSystemError(err).c_str());
    else if( !proc )
        Logger::instance()->add("findProcessByExe() returned 0. "\
            "Process not found or other error occured.");

    return proc;
}

DWORD Macro::findProcessByWindow(HWND window, int &err)
{
    DWORD proc = processDevice->findProcessByWindow(window, err);

    if( err )
        Logger::instance()->add("findProcessByWindow() exited with error code "\
            "%d (%s).", err, getSystemError(err).c_str());
    else if( !proc )
        Logger::instance()->add("findProcessByWindow() returned 0. "\
            "Process not found or other error occured.");

    return proc;
}

HWND Macro::getWindowParent(HWND child)
{
	return processDevice->getWindowParent(child);
}

HWND Macro::findWindow(std::string name, std::string classname, int &err)
{
    HWND hwnd = processDevice->findWindow(name, classname, err);

    if( !hwnd )
        Logger::instance()->add("findWindow() returned 0. Window not found " \
            "or other error occured.");

    return hwnd;
}

void Macro::findWindowList(std::string name, std::string classname,
    std::vector<HWND> &list, int &err)
{
    processDevice->findWindowList(name, classname, list, err);

    if( list.size() == 0 )
        Logger::instance()->add("findWindowList() returned 0 results. " \
            "Window(s) not found or other error occured.");
}

HWND Macro::foregroundWindow()
{
    return processDevice->foregroundWindow();
}

HWND Macro::getHwnd()
{
    return processDevice->getHwnd();
}

std::string Macro::getWindowName(HWND hwnd, int &err)
{
    return processDevice->getWindowName(hwnd, err);
}

std::string Macro::getWindowClassName(HWND hwnd, int &err)
{
	return processDevice->getWindowClassName(hwnd, err);
}

void Macro::setWindowName(HWND hwnd, std::string &name, int &err)
{
    processDevice->setWindowName(hwnd, name, err);
}

int Macro::windowValid(HWND hwnd)
{
    return processDevice->windowValid(hwnd);
}

RECT Macro::windowRect(HWND hwnd)
{
    return processDevice->windowRect(hwnd);
}

WinDC Macro::openDC(HWND hwnd)
{
    return processDevice->openDC(hwnd);
}

void Macro::closeDC(WinDC &windc)
{
    processDevice->closeDC(windc);
}

int Macro::makeColor(unsigned char r, unsigned char g, unsigned char b)
{
    return processDevice->makeColor(r, g, b);
}

unsigned char Macro::getR(int col)
{
    return processDevice->getR(col);
}

unsigned char Macro::getG(int col)
{
    return processDevice->getG(col);
}

unsigned char Macro::getB(int col)
{
    return processDevice->getB(col);
}

int Macro::getPixel(WinDC *windc, int x, int y)
{
    return processDevice->getPixel(windc, x, y);
}

void Macro::setPixel(WinDC *windc, int x, int y, int col)
{
    return processDevice->setPixel(windc, x, y, col);
}

POINT Macro::pixelSearch(WinDC *windc, int color, int x1, int y1,
    int x2, int y2, unsigned char accuracy, int step)
{
    return processDevice->pixelSearch(windc, color, x1, y1,
        x2, y2, accuracy, step);
}

void Macro::drawLine(HDC hdc, int x1, int y1, int x2, int y2, int col,
    int thickness)
{
    processDevice->drawLine(hdc, x1, y1, x2, y2, col, thickness);
}
void Macro::drawRect(HDC hdc, int x1, int y1, int x2, int y2, int col,
    int thickness)
{
    processDevice->drawRect(hdc, x1, y1, x2, y2, col, thickness);
}

void Macro::saveScreenshot(HWND hwnd, const char *fn)
{
    processDevice->saveScreenshot(hwnd, fn);
}

std::string Macro::getClipboard()
{
	return processDevice->getClipboard();
}

void Macro::setClipboard(std::string s)
{
	processDevice->setClipboard(s);
}

void Macro::showWindow(HWND hwnd, int cmd)
{
    processDevice->showWindow(hwnd, cmd);
}

unsigned long Macro::findPatternInProcess(HANDLE proc, unsigned char *bmask,
    char *szMask, unsigned long address = 0, unsigned long len = 4)
{
    return processDevice->findPatternInProcess(proc, bmask, szMask, address,
        len);
}

unsigned long Macro::getModuleAddress(DWORD procId, const char *modname)
{
	return processDevice->getModuleAddress(procId, modname);
}

void Macro::flashWindow(HWND hwnd, int count)
{
	processDevice->flashWindow(hwnd, count);
}


/* Memory functions */
char Macro::memoryReadByte(HANDLE handle, unsigned long address, int &err)
{
    //char value = memoryDevice->readByte(handle, address, err);
	char value = memoryDevice->readMemory<char>(handle, address, err);
    if( err )
        memoryReadFail(&handle, address);

    return value;
}

unsigned char Macro::memoryReadUByte(HANDLE handle, unsigned long address, int &err)
{
    unsigned char value =
	memoryDevice->readMemory<unsigned char>(handle, address, err);

    if( err )
        memoryReadFail(&handle, address);

    return value;
}

short Macro::memoryReadShort(HANDLE handle, unsigned long address , int &err)
{
    short value = memoryDevice->readMemory<short>(handle, address, err);
    if( err )
        memoryReadFail(&handle, address);

    return value;
}

unsigned short Macro::memoryReadUShort(HANDLE handle, unsigned long address , int &err)
{
    unsigned short value =
	memoryDevice->readMemory<unsigned short>(handle, address, err);

    if( err )
        memoryReadFail(&handle, address);

    return value;
}

long Macro::memoryReadInt(HANDLE handle, unsigned long address, int &err)
{
/*
    long value = memoryDevice->readInt(handle, address, err);
    if( err )
        memoryReadFail(&handle, address);
*/

	long value = memoryDevice->readMemory<long>(handle, address, err);
    if( err )
        memoryReadFail(&handle, address);

    return value;
}

unsigned long Macro::memoryReadUInt(HANDLE handle, unsigned long address, int &err)
{
    unsigned long value =
	memoryDevice->readMemory<unsigned int>(handle, address, err);

    if( err )
        memoryReadFail(&handle, address);

    return value;
}

float Macro::memoryReadFloat(HANDLE handle, unsigned long address, int &err)
{
    float value = memoryDevice->readMemory<float>(handle, address, err);

    if( err )
        memoryReadFail(&handle, address);

    return value;
}

double Macro::memoryReadDouble(HANDLE handle, unsigned long address, int &err)
{
    double value = memoryDevice->readMemory<double>(handle, address, err);
    if( err )
        memoryReadFail(&handle, address);

    return value;
}

std::string Macro::memoryReadString(HANDLE handle, unsigned long address,
    int &err, unsigned int len)
{
    std::string value = memoryDevice->readString(handle, address, err, len);
    if( err )
        memoryReadFail(&handle, address);

    return value;
}

std::wstring Macro::memoryReadUString(HANDLE handle, unsigned long address, int &err,
    unsigned int len)
{
    std::wstring value = memoryDevice->readUString(handle, address, err, len);
    if( err )
        memoryReadFail(&handle, address);

    return value;
}

char Macro::memoryReadBytePtr(HANDLE handle, unsigned long address, long offset,
    int &err)
{
    char value;
	value = memoryDevice->readMemoryPtr<char>(handle,
	address, offset, err);

    if( err )
        memoryReadFail(&handle, address);

    return value;
}

unsigned char Macro::memoryReadUBytePtr(HANDLE handle, unsigned long address,
	long offset, int &err)
{
    unsigned char value;
	value = memoryDevice->readMemoryPtr<unsigned char>(handle,
	address, offset, err);

    if( err )
        memoryReadFail(&handle, address);

    return value;
}

short Macro::memoryReadShortPtr(HANDLE handle, unsigned long address, long offset,
    int &err)
{
    short value;
	value = memoryDevice->readMemoryPtr<short>(handle,
	address, offset, err);

    if( err )
        memoryReadFail(&handle, address);

    return value;
}

unsigned short Macro::memoryReadUShortPtr(HANDLE handle, unsigned long address,
	long offset, int &err)
{
    unsigned short value;
	value = memoryDevice->readMemoryPtr<unsigned short>(handle,
	address, offset, err);

    if( err )
        memoryReadFail(&handle, address);

    return value;
}

long Macro::memoryReadIntPtr(HANDLE handle, unsigned long address, long offset, int &err)
{
    long value;
	value = memoryDevice->readMemoryPtr<long>(handle,
	address, offset, err);

    if( err )
        memoryReadFail(&handle, address);

    return value;
}

unsigned long Macro::memoryReadUIntPtr(HANDLE handle, unsigned long address, long offset,
    int &err)
{
    unsigned long value;
	value = memoryDevice->readMemoryPtr<unsigned long>(handle,
	address, offset, err);

    if( err )
        memoryReadFail(&handle, address);

    return value;
}

float Macro::memoryReadFloatPtr(HANDLE handle, unsigned long address, long offset,
    int &err)
{
    float value;
	value = memoryDevice->readMemoryPtr<float>(handle,
	address, offset, err);

    if( err )
        memoryReadFail(&handle, address);

    return value;
}

double Macro::memoryReadDoublePtr(HANDLE handle, unsigned long address, long offset,
    int &err)
{
    double value;
	value = memoryDevice->readMemoryPtr<double>(handle,
	address, offset, err);

    if( err )
        memoryReadFail(&handle, address);

    return value;
}

std::string Macro::memoryReadStringPtr(HANDLE handle, unsigned long address, long offset,
    int &err, unsigned int len)
{
    std::string value = memoryDevice->readStringPtr(handle, address, offset, err,
        len);
    if( err )
        memoryReadFail(&handle, address);

    return value;
}

std::wstring Macro::memoryReadUStringPtr(HANDLE handle, unsigned long address,
    long offset, int &err, unsigned int len)
{
    std::wstring value = memoryDevice->readUStringPtr(handle, address, offset,
        err, len);
    if( err )
        memoryReadFail(&handle, address);

    return value;
}

void Macro::memoryWriteByte(HANDLE handle, unsigned long address, unsigned char data,
	int &err)
{
    memoryDevice->writeMemory<unsigned char>(handle, address, data, err);
    if( err )
        memoryWriteFail(&handle, address);
}

void Macro::memoryWriteShort(HANDLE handle, unsigned long address, unsigned short data,
	int &err)
{
    memoryDevice->writeMemory<unsigned short>(handle, address, data, err);
    if( err )
        memoryWriteFail(&handle, address);
}

void Macro::memoryWriteInt(HANDLE handle, unsigned long address, unsigned long data,
	int &err)
{
    memoryDevice->writeMemory<unsigned long>(handle, address, data, err);
    if( err )
        memoryWriteFail(&handle, address);
}


void Macro::memoryWriteFloat(HANDLE handle, unsigned long address, float data, int &err)
{
    memoryDevice->writeMemory<float>(handle, address, data, err);
    if( err )
        memoryWriteFail(&handle, address);
}

void Macro::memoryWriteDouble(HANDLE handle, unsigned long address, double data,
	int &err)
{
    memoryDevice->writeMemory<double>(handle, address, data, err);
    if( err )
        memoryWriteFail(&handle, address);
}

void Macro::memoryWriteString(HANDLE handle, unsigned long address, char *data, int &err, unsigned int len)
{
	memoryDevice->writeString(handle, address, data, err, len);
    if( err )
        memoryWriteFail(&handle, address);
}

void Macro::memoryWriteStringPtr(HANDLE handle, unsigned long address, long offset,
	char *data, int &err, unsigned int len)
{
	memoryDevice->writeStringPtr(handle, address, offset, data, err, len);
    if( err )
        memoryWriteFail(&handle, address);
}

void Macro::memoryWriteBytePtr(HANDLE handle, unsigned long address, long offset,
    unsigned char data, int &err)
{
    memoryDevice->writeMemoryPtr<unsigned char>(handle, address,
	offset, data, err);

    if( err )
        memoryWriteFail(&handle, address);
}

void Macro::memoryWriteShortPtr(HANDLE handle, unsigned long address, long offset,
    unsigned short data, int &err)
{
    memoryDevice->writeMemoryPtr<unsigned short>(handle, address,
	offset, data, err);

    if( err )
        memoryWriteFail(&handle, address);
}

void Macro::memoryWriteIntPtr(HANDLE handle, unsigned long address, long offset,
    unsigned long data, int &err)
{
    memoryDevice->writeMemoryPtr<unsigned long>(handle, address,
	offset, data, err);

    if( err )
        memoryWriteFail(&handle, address);
}

void Macro::memoryWriteFloatPtr(HANDLE handle, unsigned long address, long offset,
    float data, int &err)
{
    memoryDevice->writeMemoryPtr<float>(handle, address,
	offset, data, err);

    if( err )
        memoryWriteFail(&handle, address);
}

void Macro::memoryWriteDoublePtr(HANDLE handle, unsigned long address, long offset,
    double data, int &err)
{
    memoryDevice->writeMemoryPtr<double>(handle, address,
	offset, data, err);

    if( err )
        memoryWriteFail(&handle, address);
}

void Macro::memoryReadBatch(HANDLE handle, unsigned long address, char *fmt,
	std::vector<CVardata> &out, int &err)
{
    memoryDevice->readBatch(handle, address, fmt, out, err);

    if( err )
        memoryReadFail(&handle, address);
}

void Macro::memoryReadFailReal(HANDLE *handle, unsigned long address,
    const char *function)
{
    // Do not show or log warnings.
    if( warningsEnabled == false )
        return;

    int err = GetLastError();
    char buffer[4096];
    snprintf((char*)&buffer, 4096,
		"WARNING: Failure reading memory from 0x%X at"\
        " 0x%x in %s(). Error code %i (%s)", (unsigned int)handle,
        (unsigned int)address, function, err, getSystemError(err).c_str());

    color_printf(COLOR_YELLOW, "%s\n", (char*)&buffer);

    Logger::instance()->add((char*)&buffer);
}

void Macro::memoryWriteFailReal(HANDLE *handle, unsigned long address,
    const char *function)
{
    // Do not show or log warnings.
    if( warningsEnabled == false )
        return;

    char buffer[4096];

    int err = GetLastError();
    snprintf((char*)&buffer, 4096,
		"WARNING: Failure writing memory to 0x%X at"\
        " 0x%x in %s(). Error code %i (%s)", (unsigned int)handle,
        (unsigned int)address, function, err, getSystemError(err).c_str());

    color_printf(COLOR_YELLOW, "%s\n", (char*)&buffer);

    Logger::instance()->add((char*)&buffer);
}


/* Filesystem functions */
std::string Macro::getPath()
{
    return filesystemDevice->getPath();
}

std::string Macro::getExecutionPath()
{
    return filesystemDevice->getExecutionPath();
}

void Macro::setExecutionPath(std::string np)
{
    filesystemDevice->setExecutionPath(np);
}

std::string Macro::getFileName(std::string fullpath)
{
    return filesystemDevice->getFileName(fullpath);
}

std::string Macro::getFilePath(std::string fullpath)
{
    return filesystemDevice->getFilePath(fullpath);
}

void Macro::getDirectory(std::string &path, std::vector<std::string> &files,
    std::string ext)
{
    filesystemDevice->getDirectory(path, files, ext);
}

int Macro::isDirectory(const std::string &path)
{
	return filesystemDevice->isDirectory(path);
}


/* Network functions */
void Macro::netInit()
{
    networkDevice->init();
}

void Macro::netPushKey(std::string &nn, std::string &nk)
{
    networkDevice->pushKey(nn, nk);
}

void Macro::netRegisterKeys()
{
    networkDevice->registerKeys();
}

void Macro::netFlushKeys()
{
    networkDevice->flushKeys();
}

NetCon Macro::netOpenCon(const char *binding, std::string &keyname)
{
    return networkDevice->openCon(binding, keyname);
}

int Macro::netListen(const NetCon &netcon)
{
    return networkDevice->listen(netcon);
}

NetCon Macro::netPollListen(const NetCon &netcon)
{
    return networkDevice->pollListen(netcon);
}

int Macro::netConnect(const NetCon &netcon, const char *addr)
{
    return networkDevice->connect(netcon, addr);
}

int Macro::netConnectStatus(const NetCon & netcon)
{
    return networkDevice->connectStatus(netcon);
}

int Macro::netPollMessages(const NetCon &netcon)
{
    return networkDevice->pollMessages(netcon);
}

std::string Macro::netGetMessage(const NetCon &netcon)
{
    return networkDevice->getMessage(netcon);
}

int Macro::netSendMessage(const NetCon &netcon, const char *buff, int size)
{
    return networkDevice->sendMessage(netcon, buff, size);
}

char *Macro::netGetAddress(const NetCon &netcon)
{
	return networkDevice->getAddress(netcon);
}

void Macro::netCloseCon(NetCon &netcon)
{
    return networkDevice->closeCon(netcon);
}

/* Timer functions */
void Macro::newTimer(std::string name)
{
    timerDevice->newTimer(name);
}

int Macro::removeTimer(std::string name)
{
    return timerDevice->removeTimer(name);
}

int Macro::startTimer(std::string name, double time)
{
    return timerDevice->startTimer(name, time);
}

int Macro::isTriggered(std::string name)
{
    return timerDevice->isTriggered(name);
}

LARGE_INTEGER Macro::getTime()
{
    return ::getNow();
}

LARGE_INTEGER Macro::getTimerFrequency()
{
	return ::getTimerFrequency();
}

double Macro::deltaTime(LARGE_INTEGER t2, LARGE_INTEGER t1)
{
    return ::deltaTime(t2, t1);
}

int Macro::ipcOpen(DWORD procId)
{
	return ipcDevice->open(procId);
}

int Macro::ipcClose()
{
	return ipcDevice->close();
}

int Macro::ipcSend(Message *in, Message *out)
{
	return ipcDevice->send(in, out);
}

void Macro::soundPlay(AudioResource *s)
{
	if( enableSound )
		s->play();
}

void Macro::soundStop(AudioResource *s)
{
    if( enableSound )
        s->stop();
}

void Macro::soundPause(AudioResource *s)
{
    if( enableSound )
		s->pause();
}

AudioResource *Macro::soundLoad(const char *f)
{
	if( !enableSound )
		return NULL;

	AudioResource *resource = new AudioResource;
	int success = resource->load(f);

	if( !success ) {
		Logger::instance()->add("Loading of audio file \'%s\' has failed", f);
		return NULL;
	}

	return resource;
}

void Macro::soundSetLooping(AudioResource *s, int loop)
{
    if( enableSound )
		s->setLooping(loop);
}

void Macro::soundSetVolume(AudioResource *s, float volume)
{
	if( enableSound )
		s->setVolume(volume);
}

int Macro::soundGetState(AudioResource *s)
{
	if( !enableSound )
		return 0;

	return s->getState();
}

/* Misc functions */
void Macro::clearScreen()
{
    ::clearCliScreen();
}

void Macro::rest(unsigned int time)
{
    Sleep(time);
    /*
    HANDLE semaphore;
    semaphore = CreateSemaphore(NULL, 0, 1, NULL);
    WaitForSingleObject(semaphore, time);
    ReleaseSemaphore(semaphore, 1, NULL);
    CloseHandle(semaphore);
    */
}

void Macro::setPriority(int priority)
{
	int err = 0;

    switch(priority)
    {
        case PRIORITY_HIGH:
            err = SetPriorityClass(GetCurrentProcess(),
			ABOVE_NORMAL_PRIORITY_CLASS);
        break;

        case PRIORITY_NORMAL:
            err = SetPriorityClass(GetCurrentProcess(),
			NORMAL_PRIORITY_CLASS);
        break;

        case PRIORITY_LOW:
            err = SetPriorityClass(GetCurrentProcess(),
			BELOW_NORMAL_PRIORITY_CLASS);
        break;
    }

	if( err == 0 )
	{
		char errbuff[256];
		snprintf((char*)&errbuff, 256,
			"Error setting priority. Error code %d (%s)",
			(int)GetLastError(), getSystemError(GetLastError()).c_str());
		Logger::instance()->add(errbuff);
	}
}

void Macro::logMessage(std::string msg)
{
    Logger::instance()->add(msg.c_str());
}

void Macro::logRaw(std::string msg)
{
    Logger::instance()->add_raw(msg.c_str());
}

int Macro::getVersion()
{
    return VERSION_NUMBER;
}

void Macro::setTextColor(int col, int bg)
{
    ::setColor(col, bg);
}

void Macro::showWarnings(int sw)
{
    warningsEnabled = sw;
}

int Macro::bitAnd(int in, int amount)
{
    return ( in & amount );
}

int Macro::bitOr(int in, int amount)
{
    return ( in | amount );
}

int Macro::bitLShift(int in, int amount)
{
    return ( in << amount );
}

int Macro::bitRShift(int in, int amount)
{
    return ( in >> amount );
}

void Macro::setWineMode(bool enabled)
{
	wineMode = enabled;

	if( keyboardDevice )
		keyboardDevice->setWineMode(enabled);
	if( mouseDevice )
		mouseDevice->setWineMode(enabled);
}
